#define PAYLOAD_SIZE 1024
#include "myproxy.h"


char is_require_keep_alive(char* header_raw) {
	char* header_raw_for_parsing = calloc(1, MAX_HEADER_SIZE);
	char* header_line;
	char* current_token;
	char* peek_token;
	char* header_line_saveptr, *token_saveptr;
	short status_code;
	char content_exist = FALSE;
	char require_keep_alive = TRUE;

	header_raw_for_parsing = strcpy(header_raw_for_parsing, header_raw);

	header_line = strtok_r(header_raw_for_parsing, "\r\n", &header_line_saveptr);
	while(header_line != NULL) {
		current_token = strtok_r(header_line, " ", &token_saveptr);
		peek_token = strtok_r(NULL, " ", &token_saveptr);
		while(1) {
			//printf("current token = <%s>, next token = <%s>\n", current_token, peek_token);
			if (((strcmp(current_token, "HTTP/1.1") == 0) || (strcmp(current_token, "HTTP/1.0") == 0)) && (peek_token != NULL)) {
//				sprintf(peek_token, "%d", responseHeader->status_code);
				status_code = atoi(peek_token);
			}

			if (strcmp(current_token, "Content-Length:") == 0 && peek_token != NULL) {
				content_exist = TRUE;
			}
			
			if (strcmp(current_token, "Transfer-Encoding:") == 0) {
				content_exist = TRUE;
			}

			if (peek_token == NULL) {
				break;
			}
			else {
				current_token = peek_token;
				peek_token = strtok_r(NULL, " ", &token_saveptr);
			}
		}
		header_line = strtok_r(NULL, "\r\n", &header_line_saveptr);
	}

	if ((content_exist == FALSE) || (status_code == 304)) {
		require_keep_alive = FALSE;
	}
	
	free(header_raw_for_parsing);
	return require_keep_alive;
}







// Case 1: Server reply HTTP 200, forward and cache data
char case1_response_process(char* response_header_raw, struct struct_response_header *responseHeader, struct struct_request_identity *requestIdentity, char need_cache) {
	char buffer;
	char current_char;
	char peek_char;
	char* content;
	char* payload;
	char* content_size_declaration_line = calloc(1, MAX_TOKEN_SIZE);
	unsigned int content_size;
	unsigned int payload_size;
	unsigned int content_written;
	char require_keep_alive;

	/* FORWARD THE HEADER TO CLIENT */
	sendn(requestIdentity->client_socket_descriptor, response_header_raw, strlen(response_header_raw));
	
	if (is_require_keep_alive(response_header_raw) == FALSE) {
		require_keep_alive = FALSE;
		//printf("connection should close\n");
	}

	/* FORWARD THE PAYLOAD TO CLIENT (IF PAYLOAD EXIST) */
	if (responseHeader->is_no_centent == FALSE) {
		switch (responseHeader->is_fix_length){
			/* Case 1: Fixed length payload */
			case TRUE:
				content = calloc(1, responseHeader->content_length);
				recvn(requestIdentity->server_socket_descriptor, content, responseHeader->content_length);
				sendn(requestIdentity->client_socket_descriptor, content, responseHeader->content_length);

				//printf("Client is %d, filename is %s\n", requestIdentity->client_socket_descriptor, requestIdentity->file_name);
				//cache content
				if (need_cache == TRUE) {
					if(cache_response(requestIdentity->file_name, responseHeader->encoding, 20, "wb") == 0){
						printf("Wrote Content-Encoding: %s type in cache file...\n", responseHeader->encoding);
					}				
					cache_response(requestIdentity->file_name, content, responseHeader->content_length, "ab");
				}
				//printf("responseHeader->content_length - %d\n", responseHeader->content_length);
				//printf("\033[1;34m%s\n\033[0m", content);
				free(content);
				break;

			/* Case 2: Variable length size */
			case FALSE:
				// Create the cache file
				if (need_cache == TRUE) {
					if(cache_response(requestIdentity->file_name, responseHeader->encoding, 20, "wb") == 0){
						printf("Wrote Content-Encoding: %s type in cache file...\n", responseHeader->encoding);
					}
				}

				do {
					memset(content_size_declaration_line, 0, MAX_TOKEN_SIZE);
					content_size = 0;
					content_written = 0;

					recvn(requestIdentity->server_socket_descriptor, &current_char, sizeof(char));
					while (1) {
						recvn(requestIdentity->server_socket_descriptor, &peek_char, sizeof(char));
						if ((current_char == '\r') && (peek_char == '\n'))
							break;
						if (((current_char >= '0') && (current_char <= '9')) || 
							((current_char >= 'A') && (current_char <= 'F')) ||
							((current_char >= 'a') && (current_char <= 'f'))) {
							content_size_declaration_line = strncat(content_size_declaration_line, &current_char, sizeof(current_char));

							//printf("Cat <%c> to line <%s>\n", current_char, content_size_declaration_line); sleep(1);
						}
						current_char = peek_char;
					};

					sscanf(content_size_declaration_line, "%X", &content_size);
					printf("Variable length content size is %s in HEX, %d in DEC\n", content_size_declaration_line, content_size);

					content_size_declaration_line = strcat(content_size_declaration_line, "\r\n");

					payload_size = strlen(content_size_declaration_line)+content_size+2;		// 2 is last \r\n
					payload = calloc(1, payload_size);

					payload = strncat(payload, content_size_declaration_line, strlen(content_size_declaration_line));
					content_written = content_written + strlen(content_size_declaration_line); //???

					if (content_size > 0) {
						content = calloc(1, content_size);
						recvn(requestIdentity->server_socket_descriptor, content, content_size);
						
						memcpy(payload + content_written, content, content_size);
						//payload = strncat(payload, content, content_size);
						
						content_written = content_written + content_size; //???
						
						//cache payload
						if (need_cache == TRUE) {
							cache_response(requestIdentity->file_name, content, content_size, "ab");
						}
						
						free(content);	// what problem ...?
					}
					memcpy(payload + content_written, "\r\n", 2);
					content_written = content_written + 2; //???
					//payload = strcat(payload, "\r\n");

					//is this in response even when there is no content???
					recvn(requestIdentity->server_socket_descriptor, &buffer, sizeof(char));				// \r
					recvn(requestIdentity->server_socket_descriptor, &buffer, sizeof(char));				// \n

					sendn(requestIdentity->client_socket_descriptor, payload, payload_size);
					
	//				printf("\033[1;34m%s\n\033[0m", payload);

					
					
					free(payload);
					//printf("\033[1;31m*************************?\n\033[0m");
					//fflush(NULL);
					
				} while (content_size > 0);
				break;
				
			default: /* Message with no content */ break;
		}
	}
	free(content_size_declaration_line);
	return require_keep_alive;
}


// Case 2a - With If-Modified-Since and no Cache-Control. (Request IMS > cached data last modify time)
void case2a_request_process(struct struct_request_identity *requestIdentity) {
	char* response_header = calloc(1, MAX_HEADER_SIZE);
	char* current_time_string = calloc(1, TIME_LENGTH);
	time_t current_time;

	// Construct HTTP 304 header
	response_header = strncat(response_header, requestIdentity->connection_type, strlen(requestIdentity->connection_type));
	response_header = strcat(response_header, " 304 Not Modified\r\n");
	response_header = strcat(response_header, "Date: ");
	current_time = time(NULL);
	to_time_string(&current_time, current_time_string);
	response_header = strcat(response_header, current_time_string);
	response_header = strcat(response_header, "\r\n");
	response_header = strcat(response_header, "Server: 3 Proxy Server\r\n");
	response_header = strcat(response_header, "Connection: close\r\n\r\n");
	
	// Send the header to client
	sendn(requestIdentity->client_socket_descriptor, response_header, strlen(response_header));
	free(response_header);
	
}